The niceRplots package and cookbook make the process of
creating publication-ready graphics in the NICE style a more
reproducible process, as well as making it easier for people new to R to
create graphics.
Within this cookbook, we will demonstrate how to use the functions
included within the niceRplots package. We will also
provide examples of plots that have been created in the NICE style.
Before we can start making charts, we first need to load all of the
relevant packages. We wont load every package here, just the ones that
we will use the most often. It is good practice to limit the number of
loaded packages to prevent masking conflicts. For this reason, we will
often use double colons :: to access specific functions
within a package (e.g. readr::read_csv()), rather than
loading the full package using library(pkg).
As an example we will create a simple bar chart using the
iris dataset. We will first create a basic chart, and then
add some additional formatting. We can see the two charts below with and
without formatting.
We can now apply the NICE theme using the
nice_gg_theme() function from the niceRplots
package, specifying the base font for the plot to be of size 12. The
nice_gg_theme() function alters several aspects of the
chart to make it consistent with the NICE brand
guidelines. These are as follows:
Fonts: changes the title font to Lora SemiBold, and all other text to Inter Regular.
Text scaling: applies a text hierarchy to the
chart using relative text sizes. Changing the optional
base_size argument will change the text size throughout the
plot. Titles and subtitles will be automatically scaled relative to this
base_size to maintain the text hierarchy. This is useful if you want to
change the chart size, as all text can be simply adjusted by changing
the base_size argument.
Colour scheme: changes line and text colours to
be consistent with the NICE brand colour palette. This is particularly
noticeable when creating faceted charts (shown later in cookbook). It
should be noted that this will not add colour to the plotted data, this
will still need to be added manually when creating the chart. For
instance, a fill colour was added in the geom_col()
argument in the above example.
Margins: adjusts the margins around the title, subtitle, and axis titles to give everything space to breathe.
Background: removes the panel background and borders.
Other: Applies major grid lines along the
y-axis. This will be appropriate for most charts, but may need to be
disabled in others by applying
theme(panel.grid.major.y = ggplot2::element_blank())
The nice_gg_theme() function isn’t designed to modify
every aspect of the chart, but to apply a general theme that will
maintain consistency with the NICE style guide across all charts. Many
aspects of the chart will still need to be modified manually. For
example, in the below chart we may choose to apply an additional theme
argument to remove the x-axis title.
Once a plot has been created and styled using
nice_gg_theme(), the next step is to apply the
finalise_plot() function. This function will create a
footer containing information on the data source, as well as adding the
NICE logo to the bottom right. It will then left-align the title,
subtitle and footer. The finalise_plot() function has 3
arguments:
plot_name: the name of the plot object, in the
example below we have saved ours as
iris_bar_themed.
source_name: the source of the underlying data. We
have used data from the iris dataset.
logo: this will determine whether the NICE logo is
included in the footer. It can have a value of “NICE” to include the
logo, or “none” to leave it blank.
After applying the finalise_plot() function, the chart
can be saved using the ggsave() function.
The sections below provide examples of how to make different types of
static chart using the ggplot2 package. These will demonstrate how to
format different charts and apply the NICE theme. For some examples we
will continue to use R’s built in iris dataset. For others
we will use data on the monthly Sub-ICB location level prescribing of 5
direct oral anticoagulants (DOACS) in England between February 2017 and
January 2022. This was downloaded from OpenPrescribing.net.
In the example below we will prepare a choropleth map of Apixaban
prescribing across Sub-ICB locations in 2021. To prepare this chart we
need two files, a dataframe containing the data we want to visualise,
and a dataframe containing the shapes for our relevant health
geographies. For these examples we will use the doacs_df
and sub_icb_shapes_2022 files that come built into the
niceRplots package.
There will be many situations where you will want to visualise data
across other geographies. The files containing shapes for other
geographies can be downloaded in .geoJSON format from the
Office for National Statistics (ONS) Open Geography
Portal.
These .geoJSON files from ONS come with different levels
of accuracy, with more accurate files having a larger file size. These
files can be distinguished by the letters at the end of the file name
(BFC > BFE > BCG > BUC). We recommend downloading the smallest
.geoJSON file (BUC), as this will greatly increase the
speed of plotting. In some cases only a very detailed file will be
available. In these cases you will need to simplify the file using the
rmapshaper package.
The code below provides examples of how to load in a
.geoJSON file as a dataframe, how to load and simplify a
file using the rmapshaper package, and how to combine
multiple shapes into a single shape (useful to give the map a darker
outside boundary).
Now that we have prepared our .geoJSON files, we can go
ahead and prepare our choropleth map.
# Declare location
here::i_am("R/plotly_theme.R")
## here() starts at C:/Users/VKam/Documents/R_work/niceRplots
# Load NICE colours
load(here::here("data", "nice_colours_full.rda"))
# Create basic bar chart (left)
plotly_iris_bar <- plot_ly(iris_bar_df,
x = ~Species,
y = ~Sepal_Width,
type = "bar")
# Create formatted chart (right)
plotly_iris_bar_formatted <- plot_ly(iris_bar_df,
x = ~Species,
y = ~Sepal_Width,
type = "bar",
marker = list(color = nice_colours_full[["bold_teal_100"]],
line = list(color = nice_colours_full[['black_100']], width = 1.5)))
plotly_iris_bar
plotly_iris_bar_formatted
# fig.show = "hold" not working for Plotly?
plotly_iris_bar_themed <- plotly_iris_bar_formatted %>%
nice_plotly_theme(chart_type = "vertical_bar",
x_title = "Species",
y_title = "Sepal Width")
Alt text (text description of message chart is showing. Mark chart as
decorative)
Source: []
Download the data for Figure x (CSV, 5.0KB).
To download the plot as a static PNG image, click on the camera icon at the top right of the plot.
Saving in other file formats (e.g. .svg or .jpg) is more complicated and requires installation of another piece of software. Read the Plotly documentation on exporting graphs as static images in R.
Use chart_type = “horizontal_bar” for histograms.
# Create chart
plotly_hist <- iris %>%
plot_ly(x = ~Sepal.Width,
color = ~Species,
# Use NICE colours - remove colour names so it maps correctly
colors = unname(nice_palettes[["discrete"]][1:3]),
type = "histogram",
# Black outline for bars
marker = list(line = list(color = nice_colours_full[['black_100']], width = 1.5)),
# Set bin width
xbins = list(size = 0.2,
start = 1.9,
end = 4.5)) %>%
# Stack bars
layout(barmode = "stack") %>%
# Add NICE theme and set axis titles
nice_plotly_theme(chart_type = "vertical_bar",
x_title = "Sepal width",
y_title = "Frequency")
plotly_hist
# Category order differs from ggplot but no big difference
Use chart_type = “vertical_bar”.
# Create chart
plotly_vbar_chart <- bar_df %>%
# Reorder chemical factor levels in decreasing order of items
mutate(chemical = reorder(chemical, -items)) %>%
plot_ly(x = ~chemical,
y = ~items,
type = "bar",
# Bold teal bars with black outline
marker = list(color = nice_colours_full[["bold_teal_100"]],
line = list(color = nice_colours_full[['black_100']], width = 1.5))) %>%
# Add NICE theme and set axis titles
nice_plotly_theme(chart_type = "vertical_bar",
x_title = "",
y_title = "Dispensed items (millions)")
Apixaban was the most prescribed DOAC in 2021
Figure x. Total DOAC medicines dispensed in primary care in England, 2020
Use chart_type = “horizontal_bar”.
# Create chart
plotly_vbar_chart <- bar_df %>%
# Reorder chemical factor levels in decreasing order of items
mutate(chemical = reorder(chemical, items)) %>%
plot_ly(x = ~items,
y = ~chemical,
type = "bar",
# Make horizontal
orientation = "h",
# Bold teal bars with black outline
marker = list(color = nice_colours_full[["bold_teal_100"]],
line = list(color = nice_colours_full[['black_100']], width = 1.5))) %>%
# Add NICE theme and set axis titles
nice_plotly_theme(chart_type = "horizontal_bar",
x_title = "Dispensed items (millions)",
y_title = "")
plotly_vbar_chart
Use chart_type = “line”.
# Create chart
plotly_line_chart <- line_df %>%
plot_ly(x = ~date,
y = ~items,
type = "scatter",
# Line with marker dot at each data point
mode = "lines+markers",
# Make line and dots teal
marker = list(color = nice_colours_full[["bold_teal_100"]])) %>%
# Add the vertical dashed line to show lockdown date. Added this before plotting the
# data so that it sits on a layer behind the line and points
add_lines(x = as.Date("2020-03-01"),
y = ~c(0, max(items)),
line = list(dash = "dash",
color = "#000000",
width = 1.5),
# Don't inherit properties of previous trace
inherit = FALSE) %>%
layout(showlegend = FALSE,
xaxis = list(type = "date", # Specify x axis is date
# Show x axis ticks
ticks = "outside",
# Format ticks as abbreviated month name and full year, e.g. Jan 2018
tickformat = "%b\n%Y",
# Set first tick
tick0 = "2017-07-01",
# Tick every 6 months
dtick = "M6"),
# Y axis ticks with commas as thousands separators
yaxis = list(tickformat = ",",
range = ~c(0, max(items)+10000)),
annotations = list(x = as.Date("2020-03-01"),
xshift = -60,
y = 180000,
text = "National lockdown\non 23 March",
xref = "x",
yref = "y",
showarrow = FALSE,
align = "right")) %>%
# Add NICE theme and set axis titles
nice_plotly_theme(chart_type = "line",
x_title = "",
y_title = "Dispensed items",
# Don't pad the axes, as ticks shown. Do not want gap between axis line and ticks
pad_axes = FALSE)
Edoxaban prescribing has increased since 2017
Figure x. Edoxaban prescribing in England, 2017-2022
# Create chart
plotly_scatter_chart <- scatter_df %>%
plot_ly(x = ~total_list_size,
y = ~items,
type = "scatter",
mode = "markers",
marker = list(color = nice_colours_full[["bold_teal_100"]])
) %>%
layout(showlegend = FALSE,
# Axis ticks with commas as thousands separators
xaxis = list(tickformat = ","),
yaxis = list(tickformat = ",")) %>%
# Add NICE theme and set axis titles
nice_plotly_theme(chart_type = "scatter",
x_title = "Primary care list size (x1000)",
y_title = "Dispensed items",
# Don't pad the axes, as ticks shown. Do not want gap between axis line and ticks
pad_axes = FALSE)
Apixaban prescribing
Items of apixaban dispensed in primary care compared to sub-ICB location
list size, July 2021
The easiest way to make faceted charts in Plotly is to make it in ggplot and then convert it into a Plotly chart using the function ggplotly.
# Create chart
ggplotly(facet_chart)
facet_template <- function(i) {
chemicals <- unique(facet_df$chemical)
facet_df %>%
filter(chemical == chemicals[[i]]) %>%
plot_ly(x = ~date,
y = ~items,
type = "scatter",
mode = "lines+markers",
marker = list(color = nice_colours[[i]]),
name = chemicals[[i]]) %>%
layout(showlegend = FALSE,
xaxis = list(type = "date", # Specify x axis is date
# Show x axis ticks
ticks = "outside",
# Format ticks as abbreviated month name and full year, e.g. Jan 2018
tickformat = "%b\n%Y",
# Outline box around plot
showline = TRUE,
mirror = "all"),
yaxis = list(showline = TRUE,
mirror = "all"),
# Subplot titles
annotations = list(xref = 'paper',
yref = 'paper',
yanchor = 'bottom',
xanchor = 'center',
align = 'center',
x = .5,
y = 1,
showarrow = FALSE,
text = chemicals[[i]],
bgcolor = nice_colours[[1]],
font = list(color = "#ffffff"))) %>%
nice_plotly_theme(chart_type = "line",
x_title = "",
y_title = "Dispensed items (thousands)",
# Don't pad the axes, as ticks shown. Do not want gap between axis line and ticks
pad_axes = FALSE)
}
plot_list <- map(1:length(unique(facet_df$chemical)), facet_template)
subplot(plot_list, shareX = TRUE, shareY = TRUE)